package com.ruoyi.hkCamera.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.ruoyi.hkCamera.common.AlarmCallBack;
import com.ruoyi.hkCamera.common.HCNetSDK;
import com.ruoyi.hkCamera.common.osSelect;
import com.ruoyi.hkCamera.config.AlarmConfig;
import com.ruoyi.hkCamera.config.CameraParamsConfig;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.List;

import static com.ruoyi.hkCamera.config.AlarmConfig.*;

/**
 * 报警布防 service类
 */
@Slf4j
@Service
public class AlarmService {


    @Autowired
    private final CameraParamsConfig cameraParamsConfig;


    public AlarmService() {
        cameraParamsConfig = SpringUtil.getBean(CameraParamsConfig.class);
        initSDKTools();
        loginOutCamera();
        loginCamera();
        alarmCallBack();
    }

    /**
     * 初始化SDK
     */
    public void initSDKTools() {
        log.info("初始化SDK Tools");
        if (hCNetSDK == null && !createSDKInstance()) {
            log.error("==============加载本地hCNetSDK错误================");
            return;
        }
        String path = System.getProperty("java.class.path");
        int firstIndex = path.lastIndexOf(System.getProperty("path.separator")) + 1;
        int lastIndex = path.lastIndexOf(File.separator) + 1;
        path = path.substring(firstIndex, lastIndex);
        hCNetSDK.NET_DVR_Init();
        hCNetSDK.NET_DVR_SetConnectTime(2000, 1);
        hCNetSDK.NET_DVR_SetReconnect(10000, true);
        hCNetSDK.NET_DVR_SetLogToFile(3, path + "/hk/sdklog", false);
    }

    /**
     * 注销相机设备
     */
    public void loginOutCamera() {
        log.info("注销相机设备");
        List<CameraParamsConfig.Account> accountList = cameraParamsConfig.getAccountList();
        for (int i = 0; i < accountList.size(); i++) {
            this.logout(i, i);
        }
    }

    /**
     * 设置回调函数
     */
    public void alarmCallBack() {
        log.info("设置回调函数");
        if (AlarmConfig.alarmCallBack == null) {
            AlarmConfig.alarmCallBack = new AlarmCallBack();
            if (!hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(AlarmConfig.alarmCallBack, null)) {
                log.error("设置回调函数失败");
                return;
            }
            log.info("设置回调函数成功");
        }
    }

    /**
     * 登录相机
     */
    public void loginCamera() {
        log.info("登录相机设备");
        List<CameraParamsConfig.Account> accountList = cameraParamsConfig.getAccountList();
        for (CameraParamsConfig.Account account : accountList) {
            String deviceType = account.getDeviceType();
            // 录像机不需要布防
            login_V40(account, !StrUtil.equals(deviceType, "21"));
        }
    }

    /**
     * 创建sdk实例方法
     */
    public boolean createSDKInstance() {
        if (hCNetSDK == null) {
            synchronized (HCNetSDK.class) {
                String strDllPath = "";
                try {
                    if (osSelect.isWindows()) {
                        strDllPath = "D:\\hk\\lib\\HCNetSDK.dll";
                    } else {
                        String path = System.getProperty("java.class.path");
                        int firstIndex = path.lastIndexOf(System.getProperty("path.separator")) + 1;
                        int lastIndex = path.lastIndexOf(File.separator) + 1;
                        path = path.substring(firstIndex, lastIndex);
                        strDllPath = path + "/hk/lib/libhcnetsdk.so";
                    }
                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);
                } catch (Exception ex) {
                    log.error("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 设备登录方法
     */
    @Async
    public void login_V40(CameraParamsConfig.Account account, boolean isAlarm) {
        String ip = account.getIp();
        String port = account.getPort();
        String user = account.getUsername();
        String psw = account.getPassword();
        String key = ip + ":" + port;
        Integer userID = devIp2UserIdMap.get(ip);
        if (userID == null) {
            userID = -1;
        }
        if (userID > -1) {
            hCNetSDK.NET_DVR_Logout(userID);
        }
        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
        m_strLoginInfo.sDeviceAddress = new byte[129];
        System.arraycopy(ip.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, ip.length());
        m_strLoginInfo.sUserName = new byte[64];
        System.arraycopy(user.getBytes(), 0, m_strLoginInfo.sUserName, 0, user.length());
        m_strLoginInfo.sPassword = new byte[64];
        System.arraycopy(psw.getBytes(), 0, m_strLoginInfo.sPassword, 0, psw.length());
        m_strLoginInfo.wPort = Short.parseShort(port);
        m_strLoginInfo.bUseAsynLogin = false;
        m_strLoginInfo.byLoginMode = 0;
        m_strLoginInfo.write();
        userID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        if(userID == -1){
            log.error(ip + "登录失败，错误码为" + hCNetSDK.NET_DVR_GetLastError());
            return;
        }
        log.info(ip + ":设备登录成功");
        // 把摄像头登录成功的userID设置到相关的devUserIDMap中
        devIp2UserIdMap.put(ip, userID);
        devUserId2IpMap.put(userID, ip);
        // 是否进行布防
        if (isAlarm) {
            Integer alarmHandle = alarmHandleMap.get(key);
            if (alarmHandle == null) {
                alarmHandle = -1;
            }
            alarmHandle = setupAlarmChan(userID, alarmHandle, key);
            alarmHandleMap.put(key, alarmHandle);
        }
    }

    /**
     * 报警布防方法
     */
    public int setupAlarmChan(int userID, int alarmHandle, String key) {
        if (userID == -1) {
            log.info(key + "请先注册");
            return userID;
        }
        if (alarmHandle < 0) {
            if (alarmCallBack == null) {
                alarmCallBack = new AlarmCallBack();
                Pointer pUser = null;
                if (!hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(alarmCallBack, pUser)) {
                    log.error("设置回调函数失败 错误码: " + hCNetSDK.NET_DVR_GetLastError());
                }
            }
            HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
            m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
            m_strAlarmInfo.byLevel = 0;
            m_strAlarmInfo.byAlarmInfoType = 1;
            m_strAlarmInfo.byDeployType = 1;
            m_strAlarmInfo.write();
            alarmHandle = hCNetSDK.NET_DVR_SetupAlarmChan_V41(userID, m_strAlarmInfo);
            if (alarmHandle == -1) {
                log.error(key + "布防失败，错误码: {}", hCNetSDK.NET_DVR_GetLastError());
                hCNetSDK.NET_DVR_Logout(userID);
                return alarmHandle;
            }
            log.info(key + "布防成功");
            return alarmHandle;
        }
        return alarmHandle;
    }


    /**
     * 设备退出方法
     */
    public void logout(Integer userId, Integer alarmHandle) {
        log.info("退出登录设备: userId={}, alarmHandle={}", userId, alarmHandle);
        hCNetSDK.NET_DVR_Logout(userId);
        hCNetSDK.NET_DVR_CloseAlarmChan_V30(alarmHandle);
    }
}
